/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package dk.rofl.maps;

import java.awt.Point;
import java.util.ArrayList;
import java.util.Random;
import java.util.Stack;

/**
 *
 * @author menderleit
 */
public abstract class MapGenerator {

    public static final int NORTH = 0;
    public static final int SOUTH = 1;
    public static final int WEST = 2;
    public static final int EAST = 3;
    private static int xPos;
    private static int yPos;
    private static Random rnd;
    private static GameMap map;
    private static Stack<Point> track;

    public static void generate(GameMap gmap) {
        map = gmap;
        rnd = new Random();
        xPos = 0;
        yPos = 0;
        
        track = new Stack();
        int longestPath = 1;
        Point endPoint = new Point();
        boolean[] canGo = new boolean[4];
        boolean done = false;

        map.fillCollisionMap(true);

        // Generate odd start pos
        while (xPos % 2 == 0) {
            xPos = rnd.nextInt(map.getWidth() - 1);
        }
        while (yPos % 2 == 0) {
            yPos = rnd.nextInt(map.getHeight() - 1);
        }

        map.setCollision(xPos, yPos, false);
        map.setStartPosition(new Point(xPos, yPos));

        // Run while there is a valid direction
        while (!done) {
            // Check which directions we can go.
            boolean cantMove = true;
            for (int i = 0; i < canGo.length; i++) {
                boolean cg = canGoDirection(i);
                if (cg) {
                    cantMove = false;
                }
                canGo[i] = cg;
            }
            if (cantMove) {
                if (track.size() > longestPath) {
                    longestPath = track.size();
                    endPoint = new Point(xPos, yPos);
                }
                // Backtrack...
                if (track.size() > 0) {                    
                    Point p = track.pop();
                    xPos = p.x;
                    yPos = p.y;
                } else {
                    map.setEndPosition(endPoint);
                    done = true;
                }
            } else {
                // Move forward...
                track.push(new Point(xPos, yPos));
                ArrayList<Integer> dirs = new ArrayList();
                for (int i = 0; i < canGo.length; i++) {
                    if (canGo[i]) {
                        dirs.add(new Integer(i));
                    }
                }
                int newDir = dirs.get(rnd.nextInt(dirs.size())).intValue();
                Point p = goDirection(newDir);
                xPos = p.x;
                yPos = p.y;
            }
        }
    }

    private static Point goDirection(int direction) {
        switch (direction) {
            case NORTH:
                map.setCollision(xPos, yPos - 1, false);
                map.setCollision(xPos, yPos - 2, false);
                yPos -= 2;
                break;

            case SOUTH:
                map.setCollision(xPos, yPos + 1, false);
                map.setCollision(xPos, yPos + 2, false);
                yPos += 2;
                break;

            case WEST:
                map.setCollision(xPos - 1, yPos, false);
                map.setCollision(xPos - 2, yPos, false);
                xPos -= 2;
                break;

            case EAST:
                map.setCollision(xPos + 1, yPos, false);
                map.setCollision(xPos + 2, yPos, false);
                xPos += 2;
                break;
        }

        Point newPos = new Point(xPos, yPos);
        return newPos;
    }

    private static boolean canGoDirection(int direction) {
        boolean canGoNewDir = false;

        switch (direction) {
            case NORTH:
                if (yPos > 2) {
                    if (map.getCollision(xPos, yPos - 2)) {
                        canGoNewDir = true;
                    }
                }
                break;

            case SOUTH:
                if (yPos + 2 < map.getHeight() - 1) {
                    if (map.getCollision(xPos, yPos + 2)) {
                        canGoNewDir = true;
                    }
                }
                break;

            case WEST:
                if (xPos > 2) {
                    if (map.getCollision(xPos - 2, yPos)) {
                        canGoNewDir = true;
                    }
                }
                break;

            case EAST:
                if (xPos + 2 < map.getWidth() - 1) {
                    if (map.getCollision(xPos + 2, yPos)) {
                        canGoNewDir = true;
                    }
                }
                break;
        }
        return canGoNewDir;
    }
}
